package com.channel.connector.ctripos.service.impl;

import com.alibaba.fastjson.JSON;
import com.channel.connector.ctripos.common.constant.AreaDataType;
import com.channel.connector.ctripos.common.constant.CtripOSCommonConstants;
import com.channel.connector.ctripos.common.constant.CtripOSCommonUtil;
import com.channel.connector.ctripos.common.constant.InitData;
import com.channel.connector.ctripos.common.exception.ServiceException;
import com.channel.connector.ctripos.common.util.DateUtil;
import com.channel.connector.ctripos.common.util.StringUtil;
import com.channel.connector.ctripos.domain.AreaDataDO;
import com.channel.connector.ctripos.domain.CtriposMapHotelDO;
import com.channel.connector.ctripos.domain.CtriposMapRateplanDO;
import com.channel.connector.ctripos.domain.CtriposMapRoomtypeDO;
import com.channel.connector.ctripos.domain.CtriposShopInfoDO;
import com.channel.connector.ctripos.dto.ResponseDTO;
import com.channel.connector.ctripos.dto.request.BatchSyncCtripRequest;
import com.channel.connector.ctripos.dto.request.SyncCtripCommodityRequest;
import com.channel.connector.ctripos.dto.request.SyncCtripHotelRequest;
import com.channel.connector.ctripos.dto.request.SyncCtripRoomTypeRequest;
import com.channel.connector.ctripos.enums.BedTypeEnum;
import com.channel.connector.ctripos.enums.CtripBedTypeEnum;
import com.channel.connector.ctripos.enums.CtripOSMappingStatusEnum;
import com.channel.connector.ctripos.enums.ErrorCodeEnum;
import com.channel.connector.ctripos.mapper.AreaDataMapper;
import com.channel.connector.ctripos.mapper.CtriposCommonMapper;
import com.channel.connector.ctripos.service.CtripOSRemoteInvokeService;
import com.channel.connector.ctripos.service.CtriposMappingService;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfAddressesTypeAddress;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfBasicRoomTypeBasicRoom;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfCategoryCodesTypeGuestRoomInfo;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfContactInfoRootType;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfErrorType;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfHotelStatsInfoTypeHotel;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfParagraphTypeText;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfPhonesTypePhone;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfRatePlanShortTypeRatePlan;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfRoomInfoTypeBedType;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfSellableProductsTypeSellableProduct;
import com.channel.connector.ctripos.webservice.staticinfo.ArrayOfStatisticsTypeStatistic;
import com.channel.connector.ctripos.webservice.staticinfo.BookingRulesType;
import com.channel.connector.ctripos.webservice.staticinfo.CompanyNameType;
import com.channel.connector.ctripos.webservice.staticinfo.ContactInfoRootType;
import com.channel.connector.ctripos.webservice.staticinfo.CountryNameType;
import com.channel.connector.ctripos.webservice.staticinfo.ErrorType;
import com.channel.connector.ctripos.webservice.staticinfo.GuestRoomType;
import com.channel.connector.ctripos.webservice.staticinfo.HotelInfoType;
import com.channel.connector.ctripos.webservice.staticinfo.HotelRatePlanType;
import com.channel.connector.ctripos.webservice.staticinfo.JudgeEnum;
import com.channel.connector.ctripos.webservice.staticinfo.MultimediaDescriptionType;
import com.channel.connector.ctripos.webservice.staticinfo.MultimediaDescriptionsType;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelDescriptiveContentNotifRQ;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelDescriptiveContentNotifRS;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelInvNotifRQ;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelInvNotifRS;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelRatePlanNotifRQ;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelRatePlanNotifRS;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelStatsNotifRQ;
import com.channel.connector.ctripos.webservice.staticinfo.OTAHotelStatsNotifRS;
import com.channel.connector.ctripos.webservice.staticinfo.POSType;
import com.channel.connector.ctripos.webservice.staticinfo.RoomInfoType;
import com.channel.connector.ctripos.webservice.staticinfo.SellableProductsType;
import com.channel.connector.ctripos.webservice.staticinfo.SourceType;
import com.channel.connector.ctripos.webservice.staticinfo.StatusEnum;
import com.channel.connector.ctripos.webservice.staticinfo.SuccessType;
import com.channel.connector.ctripos.webservice.staticinfo.TargetEnum;
import com.channel.connector.ctripos.webservice.staticinfo.TextItemsType;
import com.channel.connector.ctripos.webservice.staticinfo.TimeUnitType;
import com.channel.connector.product.domain.HotelDO;
import com.channel.connector.product.domain.RestrictDO;
import com.channel.connector.product.domain.RoomTypeDO;
import com.channel.connector.product.mapper.HotelMapper;
import com.channel.connector.product.mapper.RestrictMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: zhanwang
 * @create: 2019-03-12 10:23
 **/
@Service
@Slf4j
public class CtriposMappingServiceImpl implements CtriposMappingService {

    @Autowired
    private CtriposCommonMapper ctriposCommonMapper;

    @Autowired
    private CtripOSRemoteInvokeService ctripOSRemoteInvokeService;

    @Autowired
    private RestrictMapper restrictMapper;

    @Autowired
    private HotelMapper hotelMapper;

    @Autowired
    private AreaDataMapper areaDataMapper;

    @Override
    public ResponseDTO pushHotel(BatchSyncCtripRequest pushHotelRequestDTO) {
        if (null == pushHotelRequestDTO || CollectionUtils.isEmpty(pushHotelRequestDTO.getHotelVOs())
                || !StringUtil.isValidString(pushHotelRequestDTO.getMerchantCode())) {
            log.error("Parameter has error.");
            return new ResponseDTO(0, ErrorCodeEnum.INVALID_INPUTPARAM.errorCode, ErrorCodeEnum.INVALID_INPUTPARAM.errorDesc);
        }
        ResponseDTO responseDTO = null;
        try {
            responseDTO = batchPushHotelInfo(pushHotelRequestDTO);
        } catch (Exception e) {
            log.error("batchPushHotelInfo has en error :", e);
            if (null == responseDTO) {
                responseDTO = new ResponseDTO(0, ErrorCodeEnum.SYSTEM_EXCEPTION.errorCode, e.getMessage());
            }
        }
        return responseDTO;
    }

    private ResponseDTO batchPushHotelInfo(BatchSyncCtripRequest batchSyncCtripRequest) {
        Long startTime = System.currentTimeMillis();
        final String merchantCode = batchSyncCtripRequest.getMerchantCode();
        CtriposShopInfoDO ctriposShopInfoDO = InitData.shopIdShopMap.get(batchSyncCtripRequest.getShopId());
        if (null == ctriposShopInfoDO) {
            log.error("buildPOSType has error." + merchantCode);
            return new ResponseDTO(0, ErrorCodeEnum.SYSTEM_EXCEPTION.errorCode, "该商家没有配置接口权限");
        }
        CompanyNameType company = new CompanyNameType();
        company.setCode(ctriposShopInfoDO.getCode());
        company.setCodeContext(ctriposShopInfoDO.getCodeContext());

        SourceType.RequestorID requestorId = new SourceType.RequestorID();
        requestorId.setID(ctriposShopInfoDO.getApiId());
        requestorId.setType(ctriposShopInfoDO.getType());
        requestorId.setMessagePassword(ctriposShopInfoDO.getMessagePassword());
        requestorId.setCompanyName(company);

        SourceType source = new SourceType();
        source.setRequestorID(requestorId);

        final POSType posType = new POSType();
        posType.setSource(source);

        List<SyncCtripHotelRequest> hotelVOs = batchSyncCtripRequest.getHotelVOs();
        if (!CollectionUtils.isEmpty(hotelVOs)) {
            Map<Long, OTAHotelDescriptiveContentNotifRQ> ctripHotelInfoMap = new HashMap<>();
            Map<Long, OTAHotelInvNotifRQ> ctripRoomTypeMap = new HashMap<>();
            Map<Long, OTAHotelRatePlanNotifRQ> ctripRatePlanMap = new HashMap<>();

            Map<Long, CtriposMapHotelDO> ctripOsHotelMappingPOMap = new HashMap<>();
            Map<Long, List<CtriposMapRoomtypeDO>> ctripOsRoomTypeMappingMap = new HashMap<>();
            Map<Long, List<CtriposMapRateplanDO>> ctripOsRatePlanMappingMap = new HashMap<>();

            for (SyncCtripHotelRequest hotelVO : hotelVOs) {
                // 查酒店
                HotelDO hotelDO = hotelMapper.queryHotelInfoByHotelId(hotelVO.getHotelId());
                // 查国家
                AreaDataDO areaDataDO = new AreaDataDO();
                areaDataDO.setDataCode(hotelDO.getCountry());
                areaDataDO.setType(AreaDataType.COUNTRY);
                List<AreaDataDO> baseDataList = areaDataMapper.select(areaDataDO);
                if (!CollectionUtils.isEmpty(baseDataList)) {
                    hotelDO.setCountry(baseDataList.get(0).getCountryCode());
                }
                //1.组装数据库酒店映射对象
                CtriposMapHotelDO ctripOsHotelMappingPO = assemblyHotelMappingInfo(batchSyncCtripRequest, hotelDO);
                ctripOsHotelMappingPOMap.put(hotelDO.getHotelId(), ctripOsHotelMappingPO);

                //2.组装携程酒店信息
                final OTAHotelDescriptiveContentNotifRQ hotelDescriptiveContentNotifRQ = assemblyHotelInfo(merchantCode, posType, hotelDO);
                ctripHotelInfoMap.put(hotelDO.getHotelId(), hotelDescriptiveContentNotifRQ);


                //组装房型
                final List<RoomTypeDO> roomTypeDTOList = hotelDO.getRoomTypeList();
                Map<Long, RoomTypeDO> fcRoomTypeMap = new HashMap<>();
                for (RoomTypeDO roomTypeDTO : roomTypeDTOList) {
                    fcRoomTypeMap.put(roomTypeDTO.getRoomTypeId(), roomTypeDTO);
                }

                final List<SyncCtripRoomTypeRequest> roomTypeVOs = hotelVO.getRoomTypeVOs();
                if (!CollectionUtils.isEmpty(roomTypeVOs) && !CollectionUtils.isEmpty(hotelDO.getRoomTypeList())) {
                    //3.组装数据库房型映射信息
                    final List<CtriposMapRoomtypeDO> ctripOsRoomTypeMappingPOS = assemblyRoomTypeMappingInfo(batchSyncCtripRequest, hotelVO, hotelDO, fcRoomTypeMap);
                    ctripOsRoomTypeMappingMap.put(hotelDO.getHotelId(), ctripOsRoomTypeMappingPOS);

                    //4.组装携程房型信息
                    OTAHotelInvNotifRQ otaHotelInvNotifRQ = assemblyCtripRoomTypeInfo(merchantCode, posType, hotelVO, hotelDO, fcRoomTypeMap);
                    ctripRoomTypeMap.put(hotelDO.getHotelId(), otaHotelInvNotifRQ);
                }
                //组装子房型
                if (!CollectionUtils.isEmpty(roomTypeVOs)) {
                    //5.组装数据库子房型映射信息
                    final List<CtriposMapRateplanDO> ctripOsRatePlanMappingPOS = assemblyRatePlanMappingInfo(batchSyncCtripRequest, hotelVO, hotelDO, fcRoomTypeMap);
                    if (ctripOsRatePlanMappingPOS.size() > 0) {
                        ctripOsRatePlanMappingMap.put(hotelDO.getHotelId(), ctripOsRatePlanMappingPOS);
                    }

                    //6.组装携程子房型信息
                    final OTAHotelRatePlanNotifRQ otaHotelRatePlanNotifRQ = assemblyCtripRatePlan(merchantCode, posType, hotelVO, hotelDO, fcRoomTypeMap);
                    if (null != otaHotelRatePlanNotifRQ) {
                        ctripRatePlanMap.put(hotelDO.getHotelId(), otaHotelRatePlanNotifRQ);
                    }
                }
            }

            //生成映射关系
            try {
                if (ctripOsHotelMappingPOMap.size() > 0) {
                    List<CtriposMapHotelDO> ctripOsHotelMappingPOS = new ArrayList<>();
                    ctripOsHotelMappingPOS.addAll(ctripOsHotelMappingPOMap.values());
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsHotelMapping(ctripOsHotelMappingPOS);
                }

                if (ctripOsRoomTypeMappingMap.size() > 0) {
                    List<CtriposMapRoomtypeDO> ctripOsRoomTypeMappingPOS = new ArrayList<>();
                    ctripOsRoomTypeMappingMap.entrySet().forEach(e -> {
                        ctripOsRoomTypeMappingPOS.addAll(e.getValue());
                    });
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsRoomTypeMapping(ctripOsRoomTypeMappingPOS);
                }

                if (ctripOsRatePlanMappingMap.size() > 0) {
                    List<CtriposMapRateplanDO> ctripOsRatePlanMappingPOS = new ArrayList<>();
                    ctripOsRatePlanMappingMap.entrySet().forEach(e -> {
                        ctripOsRatePlanMappingPOS.addAll(e.getValue());
                    });
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsRatePlanMapping(ctripOsRatePlanMappingPOS);
                }
            } catch (Exception e) {
                log.error("save hotel mapping info has error.", e);
                throw new ServiceException("保存映射信息失败!", e);
            }

            List<CtriposMapHotelDO> failedHotelMappingList = new ArrayList<>();
            List<CtriposMapRoomtypeDO> failedRoomTypeMappingList = new ArrayList<>();
            List<CtriposMapRateplanDO> failedRatePlanMappingList = new ArrayList<>();
            if (ctripHotelInfoMap.size() > 0) {
                Map<Long, OTAHotelDescriptiveContentNotifRS> hotelDescriptiveContentNotifRSMap = ctripOSRemoteInvokeService.pushHotelInfo(ctripHotelInfoMap, batchSyncCtripRequest.getShopId());
                for (Map.Entry<Long, OTAHotelDescriptiveContentNotifRS> m : hotelDescriptiveContentNotifRSMap.entrySet()) {
                    final OTAHotelDescriptiveContentNotifRS response = m.getValue();
                    if (null == response || null != response.getError()) {
                        CtriposMapHotelDO ctripOsHotelMappingPO = ctripOsHotelMappingPOMap.get(m.getKey());
                        ctripOsHotelMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                        if (null != response && null != response.getError()) {
                            final ErrorType error = response.getError();
                            ctripOsHotelMappingPO.setErrorInfo(error.getShortText());
                        }
                        failedHotelMappingList.add(ctripOsHotelMappingPO);
                    }
                }
            }

            if (ctripRoomTypeMap.size() > 0) {
                final Map<Long, OTAHotelInvNotifRS> longOTAHotelInvNotifRSMap = ctripOSRemoteInvokeService.pushRoomTypeInfo(ctripRoomTypeMap, batchSyncCtripRequest.getShopId());
                for (Map.Entry<Long, OTAHotelInvNotifRS> m : longOTAHotelInvNotifRSMap.entrySet()) {
                    final OTAHotelInvNotifRS response = m.getValue();
                    if (null == response || null != response.getError()) {
                        final List<CtriposMapRoomtypeDO> ctripOsRoomTypeMappingPOS = ctripOsRoomTypeMappingMap.get(m.getKey());
                        for (CtriposMapRoomtypeDO ctripOsRoomTypeMappingPO : ctripOsRoomTypeMappingPOS) {
                            ctripOsRoomTypeMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                            if (null != response && null != response.getError()) {
                                final ErrorType error = response.getError();
                                ctripOsRoomTypeMappingPO.setErrorInfo(error.getShortText());
                            }
                            failedRoomTypeMappingList.add(ctripOsRoomTypeMappingPO);
                        }
                    }
                }
            }
            if (ctripRatePlanMap.size() > 0) {
                final Map<Long, OTAHotelRatePlanNotifRS> longOTAHotelRatePlanNotifRSMap = ctripOSRemoteInvokeService.pushRatePlanInfo(ctripRatePlanMap, batchSyncCtripRequest.getShopId());
                for (Map.Entry<Long, OTAHotelRatePlanNotifRS> m : longOTAHotelRatePlanNotifRSMap.entrySet()) {
                    final OTAHotelRatePlanNotifRS response = m.getValue();
                    if (null == response || null != response.getError()) {
                        final List<CtriposMapRateplanDO> ctripOsRatePlanMappingPOS = ctripOsRatePlanMappingMap.get(m.getKey());
                        for (CtriposMapRateplanDO ctripOsRatePlanMappingPO : ctripOsRatePlanMappingPOS) {
                            ctripOsRatePlanMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                            if (null != response && null != response.getError()) {
                                final ErrorType error = response.getError();
                                ctripOsRatePlanMappingPO.setErrorInfo(error.getShortText());
                            }
                            failedRatePlanMappingList.add(ctripOsRatePlanMappingPO);
                        }
                    }
                }
            }

            //修改状态
            try {
                if (failedHotelMappingList.size() > 0) {
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsHotelMapping(failedHotelMappingList);
                }
                if (failedRoomTypeMappingList.size() > 0) {
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsRoomTypeMapping(failedRoomTypeMappingList);
                }
                if (failedRatePlanMappingList.size() > 0) {
                    ctriposCommonMapper.batchSaveOrUpdateCtripOsRatePlanMapping(failedRatePlanMappingList);
                }
            } catch (Exception e) {
                log.error("update hotel mapping info has error.", e);
            }
        }
        log.info("batchPushHotelInfo total cost:" + (System.currentTimeMillis() - startTime));
        return new ResponseDTO(1);
    }

    /**
     * 组装携程子房型信息
     *
     * @param merchantCode
     * @param posType
     * @param hotelVO
     * @param hotelDO
     * @param roomTypeMap
     * @return
     */
    private OTAHotelRatePlanNotifRQ assemblyCtripRatePlan(String merchantCode, POSType posType, SyncCtripHotelRequest hotelVO, HotelDO hotelDO, Map<Long, RoomTypeDO> roomTypeMap) {
        OTAHotelRatePlanNotifRQ otaHotelRatePlanNotifRQ = new OTAHotelRatePlanNotifRQ();
        //头标签属性
        otaHotelRatePlanNotifRQ.setTarget(TargetEnum.PRODUCTION);
        otaHotelRatePlanNotifRQ.setPrimaryLangID(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        otaHotelRatePlanNotifRQ.setVersion(CtripOSCommonConstants.CTRIP_OS_STATIC_INFO_VERSION);
        otaHotelRatePlanNotifRQ.setTimeStamp(CtripOSCommonUtil.dateToXMLGregorianCalendar(new Date()));
        //接口认证信息
        otaHotelRatePlanNotifRQ.setPOS(posType);
        //子房型集合
        OTAHotelRatePlanNotifRQ.RatePlans ratePlans = new OTAHotelRatePlanNotifRQ.RatePlans();
        ratePlans.setHotelCode(hotelDO.getHotelId().toString());
        ratePlans.setHotelName(hotelDO.getHotelName());

        List<OTAHotelRatePlanNotifRQ.RatePlans.RatePlan> ratePlanList = new ArrayList<>();

        for (SyncCtripRoomTypeRequest roomTypeInfoDTO : hotelVO.getRoomTypeVOs()) {
            if (roomTypeMap.containsKey(roomTypeInfoDTO.getRoomTypeId())) {
                final RoomTypeDO roomTypeDO = roomTypeMap.get(roomTypeInfoDTO.getRoomTypeId());
                List<SyncCtripCommodityRequest> commodityVOs = roomTypeInfoDTO.getCommodityVOs();
                if (!CollectionUtils.isEmpty(commodityVOs)) {
                    for (SyncCtripCommodityRequest commodityVO : commodityVOs) {
                        OTAHotelRatePlanNotifRQ.RatePlans.RatePlan ratePlan = new OTAHotelRatePlanNotifRQ.RatePlans.RatePlan();
                        ratePlan.setRatePlanCode(commodityVO.getCommodityId().toString());
                        ratePlan.setRatePlanStatusType(StatusEnum.ACTIVE);
                        ratePlan.setRatePlanCategory(Integer.valueOf(CtripOSCommonConstants.PAY_METHOD_PREPAY));
                        //预定规则
                        HotelRatePlanType.BookingRules bookingRules = new HotelRatePlanType.BookingRules();
                        List<BookingRulesType.BookingRule> bookingRuleList = new ArrayList<>();
                        BookingRulesType.BookingRule bookingRule = new BookingRulesType.BookingRule();

                        //携程默认最大只有2人
                        bookingRule.setMaxTotalOccupancy(2);
                        //查价格计划预定条款
                        RestrictDO restrictQuery = new RestrictDO();
                        restrictQuery.setRatePlanId(commodityVO.getCommodityId().intValue());
                        List<RestrictDO> restrictDOS = restrictMapper.select(restrictQuery);
                        int hour = 0;
                        if (!CollectionUtils.isEmpty(restrictDOS) && restrictDOS.get(0) != null) {
                            RestrictDO restrictDO = restrictDOS.get(0);
                            hour = (restrictDO.getAdvanceBookingDays() == null ? 0 : restrictDO.getAdvanceBookingDays()) * 24;
                            if (restrictDO.getAdvanceBookingHours() != null) {
                                hour += restrictDO.getAdvanceBookingHours() / 100;
                            }
                        }
                        bookingRule.setMinAdvancedBookingOffset(hour);
                        bookingRule.setBookingOffsetUnit(TimeUnitType.HOUR);
                        bookingRuleList.add(bookingRule);
                        bookingRules.setBookingRule(bookingRuleList);
                        //房型
                        ArrayOfSellableProductsTypeSellableProduct sellableProducts = new ArrayOfSellableProductsTypeSellableProduct();
                        List<ArrayOfSellableProductsTypeSellableProduct.SellableProduct> sellableProductList = new ArrayList<>();
                        ArrayOfSellableProductsTypeSellableProduct.SellableProduct sellableProduct = new ArrayOfSellableProductsTypeSellableProduct.SellableProduct();
                        sellableProduct.setInvTypeCode(roomTypeDO.getRoomTypeId().toString());
                        sellableProductList.add(sellableProduct);
                        sellableProducts.setSellableProduct(sellableProductList);

                        //商品名称
                        ArrayOfParagraphTypeText description = new ArrayOfParagraphTypeText();
                        List<ArrayOfParagraphTypeText.Text> textList = new ArrayList<>();
                        ArrayOfParagraphTypeText.Text text = new ArrayOfParagraphTypeText.Text();
                        text.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_EN);
                        text.setValue(commodityVO.getCommodityName());
                        textList.add(text);
                        description.setText(textList);

                        ratePlan.setBookingRules(bookingRules);
                        ratePlan.setSellableProducts(sellableProducts);
                        ratePlan.setDescription(description);
                        ratePlanList.add(ratePlan);
                    }
                }
            }
        }
        if (ratePlanList.size() > 0) {
            ratePlans.setRatePlan(ratePlanList);
            otaHotelRatePlanNotifRQ.setRatePlans(ratePlans);
            return otaHotelRatePlanNotifRQ;
        }
        return null;
    }

    /**
     * 组装价格计划映射信息
     *
     * @param batchSyncCtripRequest
     * @param hotelVO
     * @param hotelDO
     * @param fcRoomTypeMap
     * @return
     */
    private List<CtriposMapRateplanDO> assemblyRatePlanMappingInfo(BatchSyncCtripRequest batchSyncCtripRequest, SyncCtripHotelRequest hotelVO, HotelDO hotelDO, Map<Long, RoomTypeDO> fcRoomTypeMap) {
        List<CtriposMapRateplanDO> ctripOsRatePlanMappingPOS = new ArrayList<>();
        for (SyncCtripRoomTypeRequest roomTypeInfoDTO : hotelVO.getRoomTypeVOs()) {
            if (fcRoomTypeMap.containsKey(roomTypeInfoDTO.getRoomTypeId())) {
                final RoomTypeDO roomTypeDTO = fcRoomTypeMap.get(roomTypeInfoDTO.getRoomTypeId());
                List<SyncCtripCommodityRequest> commodityVOs = roomTypeInfoDTO.getCommodityVOs();
                if (!CollectionUtils.isEmpty(commodityVOs)) {
                    for (SyncCtripCommodityRequest commodityVO : commodityVOs) {
                        CtriposMapRateplanDO ctriposMapRateplanDO = new CtriposMapRateplanDO();
                        ctriposMapRateplanDO.setHotelId(Integer.valueOf(hotelDO.getHotelId().toString()));
                        ctriposMapRateplanDO.setHotelName(hotelDO.getHotelName());
                        ctriposMapRateplanDO.setHotelNameEng(hotelDO.getEngHotelName());
                        ctriposMapRateplanDO.setRoomTypeId(Integer.valueOf(roomTypeDTO.getRoomTypeId().toString()));
                        ctriposMapRateplanDO.setRoomTypeName(roomTypeDTO.getRoomTypeName());
                        ctriposMapRateplanDO.setCommodityId(Integer.valueOf(commodityVO.getCommodityId().toString()));
                        ctriposMapRateplanDO.setCommodityName(commodityVO.getCommodityName());
                        ctriposMapRateplanDO.setCtripRateplanName(commodityVO.getCommodityName());
                        ctriposMapRateplanDO.setMerchantCode(batchSyncCtripRequest.getMerchantCode());
                        ctriposMapRateplanDO.setShopId(Integer.valueOf(batchSyncCtripRequest.getShopId()));
                        ctriposMapRateplanDO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
                        ctriposMapRateplanDO.setCreater(batchSyncCtripRequest.getCreator());
                        ctriposMapRateplanDO.setModifier(batchSyncCtripRequest.getCreator());
                        ctripOsRatePlanMappingPOS.add(ctriposMapRateplanDO);
                    }
                }
            }
        }
        return ctripOsRatePlanMappingPOS;
    }

    /**
     * 组装携程房型信息
     *
     * @param merchantCode
     * @param posType
     * @param hotelVO
     * @param hotelDO
     * @param fcRoomTypeMap
     * @return
     */
    private OTAHotelInvNotifRQ assemblyCtripRoomTypeInfo(String merchantCode, POSType posType, SyncCtripHotelRequest hotelVO, HotelDO hotelDO, Map<Long, RoomTypeDO> fcRoomTypeMap) {
        OTAHotelInvNotifRQ otaHotelInvNotifRQ = new OTAHotelInvNotifRQ();
        //头标签属性
        otaHotelInvNotifRQ.setTarget(TargetEnum.PRODUCTION);
        otaHotelInvNotifRQ.setPrimaryLangID(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        otaHotelInvNotifRQ.setVersion(CtripOSCommonConstants.CTRIP_OS_STATIC_INFO_VERSION);
        otaHotelInvNotifRQ.setTimeStamp(CtripOSCommonUtil.dateToXMLGregorianCalendar(new Date()));
        //接口认证信息
        otaHotelInvNotifRQ.setPOS(posType);
        //房型集合
        OTAHotelInvNotifRQ.SellableProducts sellableProducts = new OTAHotelInvNotifRQ.SellableProducts();
        sellableProducts.setHotelCode(hotelDO.getHotelId().toString());
        sellableProducts.setHotelName(hotelDO.getHotelName());

        List<SellableProductsType.SellableProduct> sellableProductList = new ArrayList<>();

        for (SyncCtripRoomTypeRequest roomTypeInfoDTO : hotelVO.getRoomTypeVOs()) {
            if (fcRoomTypeMap.containsKey(roomTypeInfoDTO.getRoomTypeId())) {
                final RoomTypeDO roomTypeDO = fcRoomTypeMap.get(roomTypeInfoDTO.getRoomTypeId());
                //单个房型
                SellableProductsType.SellableProduct sellableProduct = new SellableProductsType.SellableProduct();
                sellableProduct.setInvTypeCode(roomTypeInfoDTO.getRoomTypeId().toString());
                sellableProduct.setInvStatusType(StatusEnum.ACTIVE);

                //客房信息
                GuestRoomType guestRoom = new GuestRoomType();
                //入住人数
                List<GuestRoomType.Occupancy> occupancyList = new ArrayList<>();
                GuestRoomType.Occupancy adultOccupancy = new GuestRoomType.Occupancy();
                //成人
                adultOccupancy.setAgeQualifyingCode("10");
                adultOccupancy.setMinOccupancy(1);
                //携程只支持最大人数是2
                adultOccupancy.setMaxOccupancy(2);
                occupancyList.add(adultOccupancy);
                //房型信息
                GuestRoomType.Room room = new GuestRoomType.Room();
                room.setQuantity(StringUtils.isEmpty(roomTypeDO.getRoomNum()) ? null : Integer.valueOf(roomTypeDO.getRoomNum()));
                room.setFloor(roomTypeDO.getFloor());
                room.setSizeMeasurement(roomTypeDO.getArea());
                //扩展信息
                RoomInfoType tpaExtensions = new RoomInfoType();
                if (null != roomTypeDO.getIsWired()) {
                    RoomInfoType.Equipments equipments = new RoomInfoType.Equipments();
                    RoomInfoType.Equipments.LAN lan = new RoomInfoType.Equipments.LAN();
                    if (2 == roomTypeDO.getIsWired()) {
                        //收费
                        lan.setEnable(JudgeEnum.YES);
                        lan.setIsChargeable(JudgeEnum.YES);
                    } else if (1 == roomTypeDO.getIsWired()) {
                        //免费
                        lan.setEnable(JudgeEnum.YES);
                        lan.setIsChargeable(JudgeEnum.NO);
                    } else {
                        //无
                        lan.setEnable(JudgeEnum.NO);
                        lan.setIsChargeable(JudgeEnum.NO);
                    }
                    equipments.setLAN(lan);
                    tpaExtensions.setEquipments(equipments);
                }
                //床型
                String bedTypeStr = roomTypeDO.getBedType();
                if (!StringUtils.isEmpty(bedTypeStr)) {
                    ArrayOfRoomInfoTypeBedType bedTypes = new ArrayOfRoomInfoTypeBedType();
                    List<ArrayOfRoomInfoTypeBedType.BedType> bedTypeList = new ArrayList<>();
                    String[] bedTypeArr = bedTypeStr.split(",");
                    for (int i = 0; i < bedTypeArr.length; i++) {
                        Integer bedTypeInt = Integer.parseInt(bedTypeArr[i]);
                        if (BedTypeEnum.SINGLE.key.equals(bedTypeInt)
                                || BedTypeEnum.KING.key.equals(bedTypeInt)
                                || BedTypeEnum.TWIN.key.equals(bedTypeInt)
                                || BedTypeEnum.BUNK.key.equals(bedTypeInt)
                                || BedTypeEnum.MULTI.key.equals(bedTypeInt)) {
                            ArrayOfRoomInfoTypeBedType.BedType bedType = new ArrayOfRoomInfoTypeBedType.BedType();
                            bedType.setBedTypeCode(getCtripBedTypeCode(bedTypeInt));
                            int quantity = 1;
                            if (BedTypeEnum.SINGLE.key.equals(bedTypeInt) || BedTypeEnum.TWIN.key.equals(bedTypeInt)) {
                                quantity = 2;
                            }
                            bedType.setQuantity(quantity);
                            bedType.setCategoryCode(i);
                            bedTypeList.add(bedType);
                        }
                    }
                    if (bedTypeList.size() > 0) {
                        bedTypes.setBedType(bedTypeList);
                        tpaExtensions.setBedTypes(bedTypes);
                    }
                }

                //房型名称
                ArrayOfParagraphTypeText description = new ArrayOfParagraphTypeText();
                List<ArrayOfParagraphTypeText.Text> textList = new ArrayList<>();
                ArrayOfParagraphTypeText.Text text = new ArrayOfParagraphTypeText.Text();
                text.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_EN);
                text.setValue(roomTypeDO.getRoomTypeName());
                textList.add(text);
                description.setText(textList);
                //该房型上价格币种
                GuestRoomType.Currency currency = new GuestRoomType.Currency();
                currency.setCode(CtripOSCommonConstants.CTRIP_OS_STATIC_INFO_CURRENCY_CN);

                guestRoom.setOccupancy(occupancyList);
                guestRoom.setRoom(room);
                guestRoom.setTPAExtensions(tpaExtensions);
                guestRoom.setDescription(description);
                guestRoom.setCurrency(currency);

                sellableProduct.setGuestRoom(guestRoom);
                sellableProductList.add(sellableProduct);
            }
        }
        sellableProducts.setSellableProduct(sellableProductList);
        otaHotelInvNotifRQ.setSellableProducts(sellableProducts);
        return otaHotelInvNotifRQ;
    }

    private static String getCtripBedTypeCode(Integer fcBedTypeCode) {
        final BedTypeEnum fcBedType = BedTypeEnum.getEnumByKey(fcBedTypeCode);
        String ctripBedTypeCode = "";
        switch (fcBedType) {
            case SINGLE:
                ctripBedTypeCode = CtripBedTypeEnum.SINGLE.key;
                break;
            case KING:
                ctripBedTypeCode = CtripBedTypeEnum.KING.key;
                break;
            case TWIN:
                ctripBedTypeCode = CtripBedTypeEnum.TWIN.key;
                break;
            case BUNK:
                ctripBedTypeCode = CtripBedTypeEnum.BUNK.key;
                break;
            case MULTI:
                ctripBedTypeCode = CtripBedTypeEnum.BUNKHOUSE.key;
                break;
        }
        return ctripBedTypeCode;
    }

    /**
     * 组装房型映射信息
     *
     * @param batchSyncCtripRequest
     * @param hotelVO
     * @param hotelDO
     * @param fcRoomTypeMap
     * @return
     */
    private List<CtriposMapRoomtypeDO> assemblyRoomTypeMappingInfo(BatchSyncCtripRequest batchSyncCtripRequest, SyncCtripHotelRequest hotelVO, HotelDO hotelDO, Map<Long, RoomTypeDO> fcRoomTypeMap) {
        List<CtriposMapRoomtypeDO> ctripOsRoomTypeMappingPOS = new ArrayList<>();
        for (SyncCtripRoomTypeRequest roomTypeInfoDTO : hotelVO.getRoomTypeVOs()) {
            if (fcRoomTypeMap.containsKey(roomTypeInfoDTO.getRoomTypeId())) {
                final RoomTypeDO fcRoomTypeDTO = fcRoomTypeMap.get(roomTypeInfoDTO.getRoomTypeId());
                CtriposMapRoomtypeDO ctripOsRoomTypeMappingPO = new CtriposMapRoomtypeDO();
                ctripOsRoomTypeMappingPO.setHotelId(Integer.valueOf(hotelDO.getHotelId().toString()));
                ctripOsRoomTypeMappingPO.setHotelName(hotelDO.getHotelName());
                ctripOsRoomTypeMappingPO.setHotelNameEng(hotelDO.getEngHotelName());
                ctripOsRoomTypeMappingPO.setRoomTypeId(Integer.valueOf(fcRoomTypeDTO.getRoomTypeId().toString()));
                ctripOsRoomTypeMappingPO.setRoomName(fcRoomTypeDTO.getRoomTypeName());
                ctripOsRoomTypeMappingPO.setCtripRoomtypeName(fcRoomTypeDTO.getRoomTypeName());
                ctripOsRoomTypeMappingPO.setMerchantCode(batchSyncCtripRequest.getMerchantCode());
                ctripOsRoomTypeMappingPO.setShopId(Integer.valueOf(batchSyncCtripRequest.getShopId()));
//                ctripOsRoomTypeMappingPO.setRoomDesc(fcRoomTypeDTO.getRoomTypeDescribe());
                ctripOsRoomTypeMappingPO.setMaxperson(fcRoomTypeDTO.getMaxPerson());
                ctripOsRoomTypeMappingPO.setFloor(fcRoomTypeDTO.getFloor());
                ctripOsRoomTypeMappingPO.setExtraBed(fcRoomTypeDTO.getIsExtraBed());
                ctripOsRoomTypeMappingPO.setRoomArea(StringUtils.isEmpty(fcRoomTypeDTO.getArea()) ? null : new BigDecimal(fcRoomTypeDTO.getArea()));
                ctripOsRoomTypeMappingPO.setBroadnet(fcRoomTypeDTO.getIsWired());
                ctripOsRoomTypeMappingPO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
                ctripOsRoomTypeMappingPO.setCreater(batchSyncCtripRequest.getCreator());
                ctripOsRoomTypeMappingPO.setModifier(batchSyncCtripRequest.getCreator());
                ctripOsRoomTypeMappingPOS.add(ctripOsRoomTypeMappingPO);
            }
        }
        return ctripOsRoomTypeMappingPOS;
    }

    /**
     * 组装携程酒店信息
     *
     * @param merchantCode
     * @param posType
     * @param hotelDO
     * @return
     */
    private OTAHotelDescriptiveContentNotifRQ assemblyHotelInfo(String merchantCode, POSType posType, HotelDO hotelDO) {
        OTAHotelDescriptiveContentNotifRQ hotelDescriptiveContentNotifRQ = new OTAHotelDescriptiveContentNotifRQ();
        //头标签属性
        hotelDescriptiveContentNotifRQ.setTarget(TargetEnum.PRODUCTION);
        hotelDescriptiveContentNotifRQ.setPrimaryLangID(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        hotelDescriptiveContentNotifRQ.setVersion(CtripOSCommonConstants.CTRIP_OS_STATIC_INFO_VERSION);
        hotelDescriptiveContentNotifRQ.setTimeStamp(CtripOSCommonUtil.dateToXMLGregorianCalendar(new Date()));
        //接口认证信息
        hotelDescriptiveContentNotifRQ.setPOS(posType);
        //组装酒店基础信息
        OTAHotelDescriptiveContentNotifRQ.HotelDescriptiveContents hotelDescriptiveContents = new OTAHotelDescriptiveContentNotifRQ.HotelDescriptiveContents();
        hotelDescriptiveContents.setHotelCode(hotelDO.getHotelId().toString());

        OTAHotelDescriptiveContentNotifRQ.HotelDescriptiveContents.HotelDescriptiveContent hotelDescriptiveContent = new OTAHotelDescriptiveContentNotifRQ.HotelDescriptiveContents.HotelDescriptiveContent();
        //HotelInfoType
        HotelInfoType hotelInfoType = new HotelInfoType();
        hotelInfoType.setHotelStatus(StatusEnum.ACTIVE);
        //开业时间
        if (null != hotelDO.getOpeningDate()) {
            hotelInfoType.setWhenBuilt(DateUtil.dateToString(DateUtil.stringToDate(hotelDO.getOpeningDate()), "YYYY-MM"));
        }
        HotelInfoType.Descriptions descriptions = new HotelInfoType.Descriptions();
        HotelInfoType.Descriptions.MultimediaDescriptions multimediaDescriptions = new HotelInfoType.Descriptions.MultimediaDescriptions();
        List<MultimediaDescriptionType> multimediaDescription = new ArrayList<>();
        MultimediaDescriptionType multimediaDescriptionType = new MultimediaDescriptionType();
        TextItemsType textItems = new TextItemsType();
        List<TextItemsType.TextItem> textItemList = new ArrayList<>();
        //中文介绍
        TextItemsType.TextItem textItemCn = new TextItemsType.TextItem();
        textItemCn.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        textItemCn.setTitle(hotelDO.getHotelName());
        textItemCn.setDescription(hotelDO.getIntroduction());
        //英文介绍
        TextItemsType.TextItem textItemEn = new TextItemsType.TextItem();
        textItemEn.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_EN);
        textItemEn.setTitle(hotelDO.getEngHotelName());

        textItemList.add(textItemCn);
        textItemList.add(textItemEn);

        textItems.setTextItem(textItemList);
        multimediaDescriptionType.setTextItems(textItems);
        multimediaDescription.add(multimediaDescriptionType);
        multimediaDescriptions.setMultimediaDescription(multimediaDescription);

        //装修时间
        if (null != hotelDO.getDecorationDate()) {
            MultimediaDescriptionsType.Renovation renovation = new MultimediaDescriptionsType.Renovation();
            renovation.setRenovationCompletionDate(DateUtil.dateToString(DateUtil.stringToDate(hotelDO.getDecorationDate()), "YYYY-MM"));
            multimediaDescriptions.setRenovation(renovation);
        }
        descriptions.setMultimediaDescriptions(multimediaDescriptions);
        //客房数量
        if (hotelDO.getRoomTotalNum() != null) {
            ArrayOfCategoryCodesTypeGuestRoomInfo categoryCodes = new ArrayOfCategoryCodesTypeGuestRoomInfo();
            List<ArrayOfCategoryCodesTypeGuestRoomInfo.GuestRoomInfo> guestRoomInfoList = new ArrayList<>();
            ArrayOfCategoryCodesTypeGuestRoomInfo.GuestRoomInfo guestRoomInfo = new ArrayOfCategoryCodesTypeGuestRoomInfo.GuestRoomInfo();
            guestRoomInfo.setQuantity(hotelDO.getRoomTotalNum());
            guestRoomInfoList.add(guestRoomInfo);
            categoryCodes.setGuestRoomInfo(guestRoomInfoList);
            hotelInfoType.setCategoryCodes(categoryCodes);
        }
        //酒店坐标
        HotelInfoType.Position position = new HotelInfoType.Position();
        //维度
        position.setLatitude(null != hotelDO.getGoogleLatitude() ? hotelDO.getGoogleLatitude().toString() : "");
        //经度
        position.setLongitude(null != hotelDO.getGoogleLongitude() ? hotelDO.getGoogleLongitude().toString() : "");

        hotelInfoType.setDescriptions(descriptions);
        hotelInfoType.setPosition(position);

        //酒店联系方式
        ArrayOfContactInfoRootType contactInfos = new ArrayOfContactInfoRootType();
        List<ContactInfoRootType> contactInfoList = new ArrayList<>();
        ContactInfoRootType contactInfoRootType = new ContactInfoRootType();

        //酒店地址
        ArrayOfAddressesTypeAddress addresses = new ArrayOfAddressesTypeAddress();
        List<ArrayOfAddressesTypeAddress.Address> addressList = new ArrayList<>();
        ArrayOfAddressesTypeAddress.Address addressCN = new ArrayOfAddressesTypeAddress.Address();
        addressCN.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        CountryNameType countryNameType = new CountryNameType();
        countryNameType.setCode(hotelDO.getCountry());
//        countryNameType.setValue(hotelDO.getCountryName());
        addressCN.setCountryName(countryNameType);
        addressCN.setCityName(hotelDO.getCityName());
        addressCN.setAddressLine(hotelDO.getHotelAddress());

        ArrayOfAddressesTypeAddress.Address addressEN = new ArrayOfAddressesTypeAddress.Address();
        addressEN.setLanguage(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_EN);
        CountryNameType countryNameTypeEN = new CountryNameType();
        countryNameTypeEN.setCode(hotelDO.getCountry());
//        countryNameTypeEN.setValue(hotelDO.getCountryName());
        addressEN.setCountryName(countryNameTypeEN);
        addressEN.setCityName(hotelDO.getCityName());
        addressEN.setAddressLine(hotelDO.getEngHotelAddress());
        addressList.add(addressCN);
        addressList.add(addressEN);
        addresses.setAddress(addressList);

        //酒店联系方式
        ArrayOfPhonesTypePhone phones = new ArrayOfPhonesTypePhone();
        List<ArrayOfPhonesTypePhone.Phone> phoneList = new ArrayList<>();
        if (StringUtil.isValidString(hotelDO.getFax())) {
            ArrayOfPhonesTypePhone.Phone fax = new ArrayOfPhonesTypePhone.Phone();
            fax.setPhoneNumber(hotelDO.getFax());
            fax.setPhoneTechType("Fax");
            phoneList.add(fax);
        }
        if (StringUtil.isValidString(hotelDO.getPhone())) {
            ArrayOfPhonesTypePhone.Phone telePhone = new ArrayOfPhonesTypePhone.Phone();
            telePhone.setPhoneNumber(hotelDO.getPhone());
            telePhone.setPhoneTechType("Voice");
            phoneList.add(telePhone);
        }
        phones.setPhone(phoneList);

        contactInfoRootType.setAddresses(addresses);
        contactInfoRootType.setPhones(phones);
        contactInfoList.add(contactInfoRootType);
        contactInfos.setContactInfo(contactInfoList);
        //酒店基本信息
        hotelDescriptiveContent.setHotelInfo(hotelInfoType);
        hotelDescriptiveContent.setContactInfos(contactInfos);

        hotelDescriptiveContents.setHotelDescriptiveContent(hotelDescriptiveContent);
        hotelDescriptiveContentNotifRQ.setHotelDescriptiveContents(hotelDescriptiveContents);
        return hotelDescriptiveContentNotifRQ;
    }

    /**
     * 组装酒店映射信息
     *
     * @param batchSyncCtripRequest
     * @param hotelDO
     * @return
     */
    private CtriposMapHotelDO assemblyHotelMappingInfo(BatchSyncCtripRequest batchSyncCtripRequest, HotelDO hotelDO) {
        CtriposMapHotelDO ctriposMapHotelDO = new CtriposMapHotelDO();
        ctriposMapHotelDO.setHotelId(Integer.valueOf(hotelDO.getHotelId().toString()));
        ctriposMapHotelDO.setHotelName(hotelDO.getHotelName());
        ctriposMapHotelDO.setHotelNameEng(hotelDO.getEngHotelName());
        ctriposMapHotelDO.setCountryCode(hotelDO.getCountry());
//        ctriposMapHotelDO.setCountryName(hotelDO.getCountryName());
//        ctriposMapHotelDO.setProvinceCode(hotelDO.getProvinceCode());
//        ctriposMapHotelDO.setProvinceName(hotelDO.getProvinceName());
        ctriposMapHotelDO.setCityCode(hotelDO.getCityCode());
        ctriposMapHotelDO.setCityName(hotelDO.getCityName());
        ctriposMapHotelDO.setCtripHotelName(hotelDO.getHotelName());
        ctriposMapHotelDO.setCtripHotelNameEng(hotelDO.getEngHotelName());
        ctriposMapHotelDO.setCtripCityCode(hotelDO.getCityCode());
        ctriposMapHotelDO.setCtripCityName(hotelDO.getCityName());
        ctriposMapHotelDO.setHotelStar(hotelDO.getHotelStar());
        ctriposMapHotelDO.setLat(hotelDO.getGoogleLatitude() == null ? "" : String.valueOf(hotelDO.getGoogleLatitude()));
        ctriposMapHotelDO.setLon(hotelDO.getGoogleLongitude() == null ? "" : String.valueOf(hotelDO.getGoogleLongitude()));

//        ctriposMapHotelDO.setDescription(hotelDO.getIntroduction());
//        ctriposMapHotelDO.setDescriptionEng(hotelDO.getIntroduction());
        ctriposMapHotelDO.setOpenYear(DateUtil.stringToDate(hotelDO.getOpeningDate()));
        ctriposMapHotelDO.setFitmentYear(DateUtil.stringToDate(hotelDO.getDecorationDate()));
        ctriposMapHotelDO.setFax(hotelDO.getFax());
        ctriposMapHotelDO.setRoomQuantity(hotelDO.getRoomTotalNum());
        ctriposMapHotelDO.setTelephone(hotelDO.getPhone());
        ctriposMapHotelDO.setAddress(hotelDO.getHotelAddress());
        ctriposMapHotelDO.setAddressEng(hotelDO.getEngHotelAddress());
        ctriposMapHotelDO.setHotelTheme(hotelDO.getTheme());
        ctriposMapHotelDO.setMerchantCode(batchSyncCtripRequest.getMerchantCode());
        ctriposMapHotelDO.setShopId(Integer.valueOf(batchSyncCtripRequest.getShopId()));
        ctriposMapHotelDO.setCreater(batchSyncCtripRequest.getCreator());
        ctriposMapHotelDO.setModifier(batchSyncCtripRequest.getCreator());
        ctriposMapHotelDO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
        return ctriposMapHotelDO;
    }

    @Override
    public ResponseDTO syncHotel(BatchSyncCtripRequest batchSyncCtripRequest) {
        if (null == batchSyncCtripRequest || CollectionUtils.isEmpty(batchSyncCtripRequest.getHotelVOs())
                || StringUtils.isEmpty(batchSyncCtripRequest.getShopId())
                || StringUtils.isEmpty(batchSyncCtripRequest.getMerchantCode())) {
            log.error("Parameter has error.");
            return new ResponseDTO(0, ErrorCodeEnum.INVALID_INPUTPARAM.errorCode, ErrorCodeEnum.INVALID_INPUTPARAM.errorDesc);
        }
        final String merchantCode = batchSyncCtripRequest.getMerchantCode();
        final String modifier = batchSyncCtripRequest.getCreator();
        CtriposShopInfoDO ctriposShopInfoDO = InitData.shopIdShopMap.get(batchSyncCtripRequest.getShopId());
        if (null == ctriposShopInfoDO) {
            log.error("buildPOSType has error." + merchantCode);
            return new ResponseDTO(0, ErrorCodeEnum.SYSTEM_EXCEPTION.errorCode, "该商家没有配置接口权限");
        }
        CompanyNameType company = new CompanyNameType();
        company.setCode(ctriposShopInfoDO.getCode());
        company.setCodeContext(ctriposShopInfoDO.getCodeContext());

        SourceType.RequestorID requestorId = new SourceType.RequestorID();
        requestorId.setID(ctriposShopInfoDO.getApiId());
        requestorId.setType(ctriposShopInfoDO.getType());
        requestorId.setMessagePassword(ctriposShopInfoDO.getMessagePassword());
        requestorId.setCompanyName(company);

        SourceType source = new SourceType();
        source.setRequestorID(requestorId);

        final POSType posType = new POSType();
        posType.setSource(source);

        OTAHotelStatsNotifRQ otaHotelStatsNotifRQ = new OTAHotelStatsNotifRQ();
        //头标签属性
        otaHotelStatsNotifRQ.setTarget(TargetEnum.PRODUCTION);
        otaHotelStatsNotifRQ.setPrimaryLangID(CtripOSCommonConstants.CTRIP_OS_PRIMARY_LANG_ID_CN);
        otaHotelStatsNotifRQ.setVersion(CtripOSCommonConstants.CTRIP_OS_STATIC_INFO_VERSION);
        otaHotelStatsNotifRQ.setTimeStamp(CtripOSCommonUtil.dateToXMLGregorianCalendar(new Date()));
        //接口认证信息
        otaHotelStatsNotifRQ.setPOS(posType);

        ArrayOfStatisticsTypeStatistic statistics = new ArrayOfStatisticsTypeStatistic();
        List<ArrayOfStatisticsTypeStatistic.Statistic> statisticList = new ArrayList<>();

        for (SyncCtripHotelRequest hotelInfoDTO : batchSyncCtripRequest.getHotelVOs()) {
            ArrayOfStatisticsTypeStatistic.Statistic statistic = new ArrayOfStatisticsTypeStatistic.Statistic();
            statistic.setHotelCode(hotelInfoDTO.getHotelId().toString());
            statisticList.add(statistic);
        }
        statistics.setStatistic(statisticList);
        otaHotelStatsNotifRQ.setStatistics(statistics);
        final OTAHotelStatsNotifRS otaHotelStatsNotifRS = ctripOSRemoteInvokeService.syncHotelInfo(otaHotelStatsNotifRQ, batchSyncCtripRequest.getShopId());
        if (null == otaHotelStatsNotifRS || CollectionUtils.isEmpty(otaHotelStatsNotifRS.getTPAExtensionsOrSuccessOrError())) {
            log.error("syncHotelInfo return null.");
            return new ResponseDTO(0, ErrorCodeEnum.UNKNOWN_EXCEPTION.errorCode, ErrorCodeEnum.UNKNOWN_EXCEPTION.errorDesc);
        }
        ResponseDTO responseDTO = parseHotelMappingResult(ctriposShopInfoDO, modifier, otaHotelStatsNotifRS);
        return responseDTO;
    }

    /**
     * 解析酒店映射结果
     *
     * @param shopInfoDO
     * @param modifier
     * @param otaHotelStatsNotifRS
     * @return
     */
    private ResponseDTO parseHotelMappingResult(CtriposShopInfoDO shopInfoDO, String modifier, OTAHotelStatsNotifRS otaHotelStatsNotifRS) {
        SuccessType successType = null;
        ErrorType errorType = null;
        OTAHotelStatsNotifRS.TPAExtensions tpaExtensions = null;

        final List<Object> tpaExtensionsOrSuccessOrError = otaHotelStatsNotifRS.getTPAExtensionsOrSuccessOrError();
        for (Object o : tpaExtensionsOrSuccessOrError) {
            if (o instanceof SuccessType) {
                successType = (SuccessType) o;
            } else if (o instanceof ErrorType) {
                errorType = (ErrorType) o;
            } else if (o instanceof OTAHotelStatsNotifRS.TPAExtensions) {
                tpaExtensions = (OTAHotelStatsNotifRS.TPAExtensions) o;
            }
        }
        ResponseDTO responseDTO = null;
        if (null != successType && null != tpaExtensions) {
            //请求返回成功
            responseDTO = new ResponseDTO(1);
            ArrayOfHotelStatsInfoTypeHotel hotels = tpaExtensions.getHotels();
            if (null != hotels && !CollectionUtils.isEmpty(hotels.getHotel())) {
                List<CtriposMapHotelDO> ctripOsHotelMappingPOS = new ArrayList<>();
                List<CtriposMapRoomtypeDO> ctripOsRoomTypeMappingPOS = new ArrayList<>();
                List<CtriposMapRateplanDO> ctripOsRatePlanMappingPOS = new ArrayList<>();
                StringBuilder hotelBuilder = new StringBuilder();
                for (ArrayOfHotelStatsInfoTypeHotel.Hotel hotel : hotels.getHotel()) {
                    try {
                        StatusEnum hotelStatus = hotel.getStatus();
                        Integer hotelId = Integer.valueOf(hotel.getHotelCode());
                        CtriposMapHotelDO ctripOsHotelMappingPO = new CtriposMapHotelDO();
                        ctripOsHotelMappingPO.setHotelId(hotelId);
                        ctripOsHotelMappingPO.setMerchantCode(shopInfoDO.getMerchantCode());
                        ctripOsHotelMappingPO.setShopId(shopInfoDO.getId());
                        ctripOsHotelMappingPO.setModifier(modifier);

                        if (StatusEnum.FAILED.value.equals(hotelStatus.value)) {
                            //同步失败
                            ctripOsHotelMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                            ArrayOfErrorType errors = hotel.getErrors();
                            if (null != errors && !CollectionUtils.isEmpty(errors.getError())) {
                                List<ErrorType> errorList = errors.getError();
                                for (ErrorType type : errorList) {
                                    hotelBuilder.append(type.getShortText()).append(",");
                                }
                                ctripOsHotelMappingPO.setErrorInfo(hotelBuilder.toString());
                            }

                        } else if (StatusEnum.PENDING.value.equals(hotelStatus.value)) {
                            //同步中
                            ctripOsHotelMappingPO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
                        } else if (StatusEnum.ACTIVE.value.equals(hotelStatus.value)) {
                            //映射成功
                            ctripOsHotelMappingPO.setMapStatus(CtripOSMappingStatusEnum.Active.key);
                            ctripOsHotelMappingPO.setCtripHotelId(hotel.getCtripHotelCode());
                            //解析房型
                            ArrayOfBasicRoomTypeBasicRoom basicRooms = hotel.getBasicRooms();
                            if (null != basicRooms && !CollectionUtils.isEmpty(basicRooms.getBasicRoom())) {
                                List<ArrayOfBasicRoomTypeBasicRoom.BasicRoom> basicRoomList = basicRooms.getBasicRoom();
                                for (ArrayOfBasicRoomTypeBasicRoom.BasicRoom basicRoom : basicRoomList) {
                                    StatusEnum roomTypeStatus = basicRoom.getStatus();
                                    CtriposMapRoomtypeDO ctripOsRoomTypeMappingPO = new CtriposMapRoomtypeDO();
                                    ctripOsRoomTypeMappingPO.setHotelId(hotelId);
                                    ctripOsRoomTypeMappingPO.setRoomTypeId(Integer.valueOf(basicRoom.getRoomCode()));
                                    ctripOsRoomTypeMappingPO.setMerchantCode(shopInfoDO.getMerchantCode());
                                    ctripOsRoomTypeMappingPO.setShopId(shopInfoDO.getId());
                                    ctripOsRoomTypeMappingPO.setModifier(modifier);

                                    if (StatusEnum.PENDING.value.equals(roomTypeStatus.value)) {
                                        ctripOsRoomTypeMappingPO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
                                    } else if (StatusEnum.FAILED.value.equals(roomTypeStatus.value)) {
                                        ctripOsRoomTypeMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                                        ArrayOfErrorType roomTypeErrors = basicRoom.getErrors();
                                        if (null != roomTypeErrors && !CollectionUtils.isEmpty(roomTypeErrors.getError())) {
                                            ErrorType roomTypeError = roomTypeErrors.getError().get(0);
                                            ctripOsRoomTypeMappingPO.setErrorInfo(roomTypeError.getShortText());
                                        }
                                    } else if (StatusEnum.ACTIVE.value.equals(roomTypeStatus.value)) {
                                        ctripOsRoomTypeMappingPO.setMapStatus(CtripOSMappingStatusEnum.Active.key);
                                        ctripOsRoomTypeMappingPO.setCtripRoomtypeId(basicRoom.getCtripRoomCode());
                                        //解析子房型
                                        ArrayOfRatePlanShortTypeRatePlan ratePlans = basicRoom.getRatePlans();
                                        if (null != ratePlans && !CollectionUtils.isEmpty(ratePlans.getRatePlan())) {
                                            for (ArrayOfRatePlanShortTypeRatePlan.RatePlan ratePlan : ratePlans.getRatePlan()) {
                                                StatusEnum ratePlanStatus = ratePlan.getStatus();
                                                CtriposMapRateplanDO ctripOsRatePlanMappingPO = new CtriposMapRateplanDO();
                                                ctripOsRatePlanMappingPO.setCommodityId(Integer.valueOf(ratePlan.getRatePlanCode()));
                                                ctripOsRatePlanMappingPO.setMerchantCode(shopInfoDO.getMerchantCode());
                                                ctripOsRatePlanMappingPO.setShopId(shopInfoDO.getId());
                                                ctripOsRatePlanMappingPO.setModifier(modifier);

                                                if (StatusEnum.PENDING.value.equals(ratePlanStatus.value)) {
                                                    ctripOsRatePlanMappingPO.setMapStatus(CtripOSMappingStatusEnum.Pending.key);
                                                } else if (StatusEnum.FAILED.value.equals(ratePlanStatus.value)) {
                                                    ctripOsRatePlanMappingPO.setMapStatus(CtripOSMappingStatusEnum.Failed.key);
                                                    ArrayOfErrorType ratePlanErrors = ratePlan.getErrors();
                                                    if (null != ratePlanErrors && !CollectionUtils.isEmpty(ratePlanErrors.getError())) {
                                                        ErrorType ratePlanError = ratePlanErrors.getError().get(0);
                                                        ctripOsRatePlanMappingPO.setErrorInfo(ratePlanError.getShortText());
                                                    }
                                                } else if (StatusEnum.ACTIVE.value.equals(ratePlanStatus.value)) {
                                                    ctripOsRatePlanMappingPO.setMapStatus(CtripOSMappingStatusEnum.Active.key);
                                                    ctripOsRatePlanMappingPO.setCtripRateplanId(ratePlan.getCtripRatePlanCode());
                                                }
                                                ctripOsRatePlanMappingPOS.add(ctripOsRatePlanMappingPO);
                                            }
                                        }
                                    }
                                    ctripOsRoomTypeMappingPOS.add(ctripOsRoomTypeMappingPO);
                                }
                            }
                        }
                        ctripOsHotelMappingPOS.add(ctripOsHotelMappingPO);
                    } catch (Exception e) {
                        log.error("batchSyncHotelInfo has error,param:" + JSON.toJSONString(hotel), e);
                    } finally {
                        hotelBuilder.setLength(0);
                    }
                }
                if (ctripOsHotelMappingPOS.size() > 0) {
                    ctriposCommonMapper.batchUpdateCtripOsHotelMapping(ctripOsHotelMappingPOS);
                }
                if (ctripOsRoomTypeMappingPOS.size() > 0) {
                    ctriposCommonMapper.batchUpdateCtripOsRoomTypeMapping(ctripOsRoomTypeMappingPOS);
                }
                if (ctripOsRatePlanMappingPOS.size() > 0) {
                    ctriposCommonMapper.batchUpdateCtripOsRatePlanMapping(ctripOsRatePlanMappingPOS);
                }
            }
        } else {
            responseDTO = new ResponseDTO(0, ErrorCodeEnum.UNKNOWN_EXCEPTION.errorCode, ErrorCodeEnum.UNKNOWN_EXCEPTION.errorDesc);
            if (null != errorType) {
                responseDTO.setFailCode(errorType.getCode());
                responseDTO.setFailReason(errorType.getShortText());
            }
        }
        return responseDTO;
    }
}
